package l1j.server.server.clientpackets;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;

import l1j.opqlo.Server.L1World.L1World;
import l1j.opqlo.假人系統.RobotTable;
import l1j.server.Config;
import l1j.server.echo.ClientThread;
import l1j.server.server.BadNamesList;
import l1j.server.server.IdFactory;
import l1j.server.server.datatables.CharObjidTable;
import l1j.server.server.datatables.CharacterTable;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.datatables.lock.CharSkillReading;
import l1j.server.server.model.BeginnerTable;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_CharCreateStatus;
import l1j.server.server.serverpackets.S_NewCharPacket;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.templates.L1Account;
import l1j.server.server.templates.L1Skills;
import l1j.server.server.utils.CalcInitHpMp;


/**
 * 處理收到由客戶端傳來建立角色的封包
 */
public class C_CreateChar extends ClientBasePacket {

	private static Logger _log = Logger.getLogger(C_CreateChar.class.getName());

	private static final String C_CREATE_CHAR = "[C] C_CreateChar";

	private static final int[] ORIGINAL_STR = new int[]{ 13, 16, 11, 8, 12, 13, 11 };

	private static final int[] ORIGINAL_DEX = new int[]{ 10, 12, 12, 7, 15, 11, 10 };

	private static final int[] ORIGINAL_CON = new int[]{ 10, 14, 12, 12, 8, 14, 12 };

	private static final int[] ORIGINAL_WIS = new int[]{ 11, 9, 12, 12, 10, 12, 12 };

	private static final int[] ORIGINAL_CHA = new int[]{ 13, 12, 9, 8, 9, 8, 8 };

	private static final int[] ORIGINAL_INT = new int[]{ 10, 8, 12, 12, 11, 11, 12 };

	private static final int[] ORIGINAL_AMOUNT = new int[]{ 8, 4, 7, 16, 10, 6, 10 };

//	private static final String CLIENT_LANGUAGE_CODE = Config.CLIENT_LANGUAGE_CODE;

	public static int NewChar =0;//opqlo 黑盒子即時資訊

	//TODO 台版3.3C新隱藏之谷座標
	private static final int[] MALE_LIST = new int[] { 0, 61, 138, 734, 2786, 6658, 6671 };

	private static final int[] FEMALE_LIST = new int[] { 1, 48, 37, 1186, 2796, 6661, 6650 };

	private static final int[] LOCX_LIST = new int[] { 32679, 32679, 32679, 32679, 32679, 32679, 32679 };

	private static final int[] LOCY_LIST = new int[] { 32866, 32866, 32866, 32866, 32866, 32866, 32866 };

	private static final short[] MAPID_LIST = new short[] { 2005, 2005, 2005, 2005, 2005, 2005, 2005 };

	private static void initNewChar(final ClientThread client,final  L1PcInstance pc)
	throws IOException, Exception {

		pc.setId(IdFactory.getInstance().nextId());
		//TODO 角色誕生by99團隊
		pc.setBirthday();
		//TODO 角色誕生by99團隊
		if (pc.get_sex() == 0) {
			pc.setClassId(MALE_LIST[pc.getType()]);
		} else {
			pc.setClassId(FEMALE_LIST[pc.getType()]);
		}
		pc.setX(LOCX_LIST[pc.getType()]);
		pc.setY(LOCY_LIST[pc.getType()]);
		pc.setMap(MAPID_LIST[pc.getType()]);
		pc.setHeading(0);
		pc.setLawful(0);

		final int initHp = CalcInitHpMp.calcInitHp(pc);
		final int initMp = CalcInitHpMp.calcInitMp(pc);
		pc.addBaseMaxHp((short) initHp);
		pc.setCurrentHp((short) initHp);
		pc.addBaseMaxMp((short) initMp);
		pc.setCurrentMp((short) initMp);
		pc.resetBaseAc();
		pc.setTitle("");
		pc.setClanid(0);
		NewChar++;//opqlo 黑盒子即時資訊
		// TODO 玩家誕生了 by terry0412
		String msg = "";
		if (pc.isCrown()) {
			msg = "君王";
		} else if (pc.isKnight()) {
			msg = "劍士";
		} else if (pc.isElf()) {
			msg = "精靈";
		} else if (pc.isWizard()) {
			msg = "巫師";
		} else if (pc.isDarkelf()) {
			msg = "刺客";
		} else if (pc.isDragonKnight()) {
			msg = "龍騎士";
		} else if (pc.isIllusionist()) {
			msg = "幻術師";
		}
		for (final L1PcInstance allpc : L1World.getInstance().getAllPlayers()) {
			if (allpc != null) {
				allpc.sendPackets(new S_SystemMessage("★玩家【" + pc.getName()+ "】誕生了，職業：【" + msg + "】★"));
			}
		}
		pc.setClanRank(0);
		pc.set_food(40);
		pc.setAccessLevel((short) client.getAccount().get_access_level());
		if (pc.getAccessLevel() == 200) {
			pc.setGm(true);
			pc.setMonitor(false);
		} else if (pc.getAccessLevel() == 100) {
			pc.setGm(false);
			pc.setMonitor(true);
		} else {
			pc.setGm(false);
			pc.setMonitor(false);
		}
		pc.setGmInvis(false);
		pc.setExp(0);
		pc.setHighLevel(0);
		pc.setStatus(0);
		pc.setClanname("");
		pc.setBonusStats(0);
		pc.setElixirStats(0);
		pc.resetBaseMr();
		pc.setElfAttr(0);
		pc.set_PKcount(0);
		pc.setPkCountForElf(0);
		pc.setExpRes(0);
		pc.setPartnerId(0);
		pc.setOnlineStatus(0);
		pc.setHomeTownId(0);
		pc.setContribution(0);
		pc.setBanned(false);
		pc.setKarma(0);
		final byte str = (byte) (45 - pc.getBaseStr()),
				dex = (byte) (45 - pc.getBaseDex()),
				Int = (byte) (45 - pc.getBaseInt()),
				con = (byte) (45 - pc.getBaseCon()),
				wis = (byte) (45 - pc.getBaseWis()),
				cha = (byte) (45 - pc.getBaseCha());
		
		pc.addBaseStr(str);
		pc.addBaseCha(cha);
		pc.addBaseCon(con);
		pc.addBaseInt(Int);
		pc.addBaseDex(dex);
		pc.addBaseWis(wis);
		
		if (pc.isWizard()) {// // 法師技能
			final int object_id = pc.getId();
			final L1Skills l1skills = SkillsTable.getInstance().getTemplate(4); // EB
			final String skill_name = l1skills.getName();
			final int skill_id = l1skills.getSkillId();

			CharSkillReading.get().spellMastery(object_id, skill_id, skill_name, 0, 0); // 資料庫紀錄
		}
		// 紀錄人物帳號
		pc.setAccountName(client.getAccountName());
		// 初始化數值
		pc.refresh();

		client.out().encrypt(new S_NewCharPacket(pc));
		// 建立人物資料
		CharacterTable.getInstance().storeNewCharacter(pc);
		// 紀錄人物初始化資料
		CharacterTable.saveNewCharStatus(pc);
		// 給予新手道具
		BeginnerTable.get().giveItem(pc);
		// 加入建立PC OBJID資料
		CharObjidTable.get().addChar(pc.getId(), pc.getName());

	}

	private static boolean isAlphaNumeric(final String s) {
		boolean flag = true;
		final char ac[] = s.toCharArray();
		int i = 0;
		do {
			if (i >= ac.length) {
				break;
			}
			if (!Character.isLetterOrDigit(ac[i])) {
				flag = false;
				break;
			}
			i++;
		} while (true);
		return flag;
	}

//	private static boolean isInvalidName(final String name) {
//		int numOfNameBytes = 0;
//		try {
//			numOfNameBytes = name.getBytes(CLIENT_LANGUAGE_CODE).length;
//		} catch (final UnsupportedEncodingException e) {
//			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
//			return false;
//		}
//
//		// XXX - 規則還沒確定
//		// 雙字節字符或5個字符以上或整個超過 12個字節就視為一個無效的名稱
//		if(5 < numOfNameBytes - name.length() || 13 < numOfNameBytes){
//			return true;
//		}
//
//		if (isAlphaNumeric(name)
//				// 字串位元長度 > 4 時，才允許建立名稱
//				&& 3 < numOfNameBytes
//				&& !BadNamesList.getInstance().isBadName(name)) {
//			return false;
//		}
//		return true;
//	}
	private boolean isInvalidName(final String name) {
		int numOfNameBytes = 0;
		final String CLIENT_LANGUAGE_CODE = Config.CLIENT_LANGUAGE_CODE;
		try {
			numOfNameBytes = name.getBytes(CLIENT_LANGUAGE_CODE).length;
		} catch (final UnsupportedEncodingException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
			return false;
		}
		if (isAlphaNumeric(name)
				// 字串位元長度 > 4 時，才允許建立名稱
				&& numOfNameBytes >= 3 && numOfNameBytes <= 12
				&& !BadNamesList.getInstance().isBadName(name)) {
			return false;
		}
		return true;
	}

	@Override
	public String getType() {
		return C_CREATE_CHAR;
	}

	@Override
	public void start(final byte[] decrypt, final ClientThread client) {
		try {
			// 資料載入
			this.read(decrypt);
		final L1PcInstance pc = new L1PcInstance();
		String name = Matcher.quoteReplacement(this.readS());
		if(name == null){
			return;
		}
		final L1Account account = client.getAccount();
		final int characterSlot = account.get_character_slot();
		final int maxAmount = Config.DEFAULT_CHARACTER_SLOT + characterSlot;

		name = name.replaceAll("\\s", "");
		name = name.replaceAll("　", "");
		if (name.length() == 0) {
			client.out().encrypt(new S_CharCreateStatus(S_CharCreateStatus.REASON_INVALID_NAME));
			return;
		}
		// 名稱是否包含禁止字元
		if (isInvalidName(name)) {
			client.out().encrypt(new S_CharCreateStatus(S_CharCreateStatus.REASON_INVALID_NAME));
			return;
		}
		// 檢查名稱是否以被使用
					if (CharObjidTable.get().charObjid(name) != 0 || RobotTable.getInstance().checkName(name)) {
						client.out().encrypt(new S_CharCreateStatus(S_CharCreateStatus.REASON_ALREADY_EXSISTS));
						return;
					}
		/*if (CharacterTable.doesCharNameExist(name)) {
			_log.fine("charname: " + pc.getName()
					+ " already exists. creation failed.");
			S_CharCreateStatus s_charcreatestatus1 = new S_CharCreateStatus(S_CharCreateStatus.REASON_ALREADY_EXSISTS);
			client.out().encrypt(s_charcreatestatus1);
			return;
		}*/
						// 已創人物數量
						final int countCharacters = client.getAccount().get_countCharacters();
						if (countCharacters >= maxAmount) {
							client.out().encrypt(new S_CharCreateStatus(S_CharCreateStatus.REASON_WRONG_AMOUNT));
							return;
						}

	/*	int countCharacters = client.getAccount().get_countCharacters();
		if (countCharacters >= maxAmount) {
			_log.fine("帳號: " + client.getAccountName() + " 建立超過" + maxAmount+ "個角色人物。");
			S_CharCreateStatus s_charcreatestatus1 = new S_CharCreateStatus(S_CharCreateStatus.REASON_WRONG_AMOUNT);
			client.out().encrypt(s_charcreatestatus1);
			return;
		}*/

		pc.setName(name);
		pc.setType(this.readC());
		pc.set_sex(this.readC());
		pc.addBaseStr((byte) this.readC());
		pc.addBaseDex((byte) this.readC());
		pc.addBaseCon((byte) this.readC());
		pc.addBaseWis((byte) this.readC());
		pc.addBaseCha((byte) this.readC());
		pc.addBaseInt((byte) this.readC());

		boolean isStatusError = false;
		final int originalStr = ORIGINAL_STR[pc.getType()];
		final int originalDex = ORIGINAL_DEX[pc.getType()];
		final int originalCon = ORIGINAL_CON[pc.getType()];
		final int originalWis = ORIGINAL_WIS[pc.getType()];
		final int originalCha = ORIGINAL_CHA[pc.getType()];
		final int originalInt = ORIGINAL_INT[pc.getType()];
		final int originalAmount = ORIGINAL_AMOUNT[pc.getType()];

		if (pc.getBaseStr() < originalStr
				|| pc.getBaseDex() < originalDex
				|| pc.getBaseCon() < originalCon
				|| pc.getBaseWis() < originalWis
				|| pc.getBaseCha() < originalCha
				|| pc.getBaseInt() < originalInt

				|| pc.getBaseStr() > originalStr + originalAmount
				|| pc.getBaseDex() > originalDex + originalAmount
				|| pc.getBaseCon() > originalCon + originalAmount
				|| pc.getBaseWis() > originalWis + originalAmount
				|| pc.getBaseCha() > originalCha + originalAmount
				|| pc.getBaseInt() > originalInt + originalAmount) {
			isStatusError = true;
		}

		final int statusAmount = pc.getDex() + pc.getCha() + pc.getCon()+ pc.getInt() + pc.getStr() + pc.getWis();

		if (statusAmount != 75 || isStatusError) {
			client.out().encrypt(new S_CharCreateStatus(S_CharCreateStatus.REASON_WRONG_AMOUNT));
			return;
		}
		_log.fine("charname: " + pc.getName() + " classId: " + pc.getClassId());
		pc.setOriginalStr(pc.getBaseStr());
		pc.setOriginalDex(pc.getBaseDex());
		pc.setOriginalCon(pc.getBaseCon());
		pc.setOriginalWis(pc.getBaseWis());
		pc.setOriginalCha(pc.getBaseCha());
		pc.setOriginalInt(pc.getBaseInt());
		client.getAccount().set_countCharacters(countCharacters + 1);
		client.out().encrypt(new S_CharCreateStatus(S_CharCreateStatus.REASON_OK));
		initNewChar(client, pc);
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);

		} finally {
			this.over();
		}
	}
}
